#ifndef GNLMODEL_h
#define GNLMODEL_h

#include "gnlDataModel.h"
#include "gnlFBXScene.h"
#include "gnlTexture.h"
#include "gnlShader.h"

#include <iostream>

using namespace std;

class gnlModel{

private:
	gnlFBXScene *pFBXScene; //When necessary import external model to gnl format
	gnlScene *pGNLScene;
	// 
public:

	gnlModel(){ pFBXScene = NULL; pGNLScene = NULL;}


	gnlMaterial* getMaterial (){
		return pGNLScene->material[0];		
	}

	int getNumberOfMeshes(){
		return pGNLScene->numberOfMeshes;
	}

	const gnlMesh& getMesh(int meshIndex){
		
		if(meshIndex < pGNLScene->numberOfMeshes)
			return *pGNLScene->mesh[meshIndex];

		return *pGNLScene->mesh[0]; // Not found mesh, return first
	}

	int importModel(const char *fileName){// support(obj/collada/fbx/3ds) formats
		
		pFBXScene = new gnlFBXScene();
		pFBXScene->initialize();
		
		pGNLScene =	pFBXScene->loadScene(fileName);

		if(!pGNLScene){
			return -1;
		}

		for(int i = 0; i< pGNLScene->numberOfMaterials; i++){
			if(pGNLScene->material[i]->haveDiffuseTexture()){
				gnlTextureManager::AddTexture(*pGNLScene->material[i]->diffuseTexture[0]);
			}

		}

		return 1;

	}

	void destroy(){
		
		if(pFBXScene){
			pFBXScene->destroy();
			pFBXScene = NULL;
		}
		
		if(pGNLScene){
			pGNLScene->destroy();
			pGNLScene = NULL;
		}
	}


	void debug(){
		

		gnlScene *scene = pGNLScene;
		for( unsigned int i = 0; i < scene->numberOfMeshes; i++){
			int n = scene->mesh[i]->numberOfTriangles;
			cout<<"Mesh "<<i <<" com "<< n<<" triangulos"<<endl;
			
			for( unsigned int j = 0; j < scene->mesh[i]->numberOfTriangles; j++){
				cout<<"\n\nPoligono "<<j<<endl;
				int		triIndex1 = scene->mesh[i]->pTriangle[j].vertexIndex[0];
				int		triIndex2 = scene->mesh[i]->pTriangle[j].vertexIndex[1];
				int		triIndex3 = scene->mesh[i]->pTriangle[j].vertexIndex[2];
				
				//int uvIndex1 = scene->mesh[i]->pTriangle[j].uvIndex[0];
				//int uvIndex2 = scene->mesh[i]->pTriangle[j].uvIndex[1];
				//int uvIndex3 = scene->mesh[i]->pTriangle[j].uvIndex[2];
				int matIndex = scene->mesh[i]->pTriangle[j].materialIndex;
				
				cout<<"Material:"<<matIndex<<endl;
				
				cout<<"Binormal:"<<scene->mesh[i]->pTriangle[j].binormal[0].x<<" "<<scene->mesh[i]->pTriangle[j].binormal[0].y<<" "
					<<scene->mesh[i]->pTriangle[j].binormal[0].z<<endl;
				
				cout<<"Tangent:"<<scene->mesh[i]->pTriangle[j].tangent[0].x<<" "<<scene->mesh[i]->pTriangle[j].tangent[0].y<<" "
					<<scene->mesh[i]->pTriangle[j].tangent[0].z<<endl;

				cout<<"Normal:"<<scene->mesh[i]->pTriangle[j].normal[0].x<<" "<<scene->mesh[i]->pTriangle[j].normal[0].y<<" "
					<<scene->mesh[i]->pTriangle[j].normal[0].z<<endl;
				cout<<"Coord. texture:"<<scene->mesh[i]->pTriangle[j].uvCoord[0].u<<"  "<<scene->mesh[i]->pTriangle[j].uvCoord[0].v<<endl;
				cout<<scene->mesh[i]->pVertex[triIndex1].x<<" "<<scene->mesh[i]->pVertex[triIndex1].y<<" "<<scene->mesh[i]->pVertex[triIndex1].z<<" "<<endl;
				
				

				cout<<"Binormal:"<<scene->mesh[i]->pTriangle[j].binormal[1].x<<" "<<scene->mesh[i]->pTriangle[j].binormal[1].y<<" "
					<<scene->mesh[i]->pTriangle[j].binormal[1].z<<endl;
				
				cout<<"Tangent:"<<scene->mesh[i]->pTriangle[j].tangent[1].x<<" "<<scene->mesh[i]->pTriangle[j].tangent[1].y<<" "
					<<scene->mesh[i]->pTriangle[j].tangent[1].z<<endl;

				cout<<"Normal:"<<scene->mesh[i]->pTriangle[j].normal[1].x<<" "<<scene->mesh[i]->pTriangle[j].normal[1].y<<" "
					<<scene->mesh[i]->pTriangle[j].normal[1].z<<endl;
				cout<<"Coord. texture:"<<scene->mesh[i]->pTriangle[j].uvCoord[1].u<<"  "<<scene->mesh[i]->pTriangle[j].uvCoord[1].v<<endl;
				cout<<scene->mesh[i]->pVertex[triIndex2].x<<" "<< scene->mesh[i]->pVertex[triIndex2].y<<" "<< scene->mesh[i]->pVertex[triIndex2].z<<" "<<endl;
				
				

				cout<<"Binormal:"<<scene->mesh[i]->pTriangle[j].binormal[2].x<<" "<<scene->mesh[i]->pTriangle[j].binormal[2].y<<" "
					<<scene->mesh[i]->pTriangle[j].binormal[2].z<<endl;
				
				cout<<"Tangent:"<<scene->mesh[i]->pTriangle[j].tangent[2].x<<" "<<scene->mesh[i]->pTriangle[j].tangent[2].y<<" "
					<<scene->mesh[i]->pTriangle[j].tangent[2].z<<endl;

				cout<<"Normal:"<<scene->mesh[i]->pTriangle[j].normal[2].x<<" "<<scene->mesh[i]->pTriangle[j].normal[2].y<<" "
					<<scene->mesh[i]->pTriangle[j].normal[2].z<<endl;
				cout<<"Coord. texture:"<<scene->mesh[i]->pTriangle[j].uvCoord[2].u<<"  "<<scene->mesh[i]->pTriangle[j].uvCoord[2].v<<endl;


				cout<<scene->mesh[i]->pVertex[triIndex3].x<<" "<< scene->mesh[i]->pVertex[triIndex3].y<<" "<< scene->mesh[i]->pVertex[triIndex3].z<<" "<<endl;
			}

		}
		
	}


	void renderAxis(){

		glBegin(GL_LINES);
		glColor3f(1,0,0);
		glVertex3f(0,0,0);
		glVertex3f(50,0,0);

		glColor3f(0,1,0);
		glVertex3f(0,0,0);
		glVertex3f(0,50,0);

		glColor3f(0,0,1);
		glVertex3f(0,0,0);
		glVertex3f(0,0,50);
		glEnd();
	}
	void renderAll(gnlShaderProgram &shaderProgram){//, gnlTexture &normalMap){
		gnlScene *scene = pGNLScene;
		int triIndex1 = 0;
		int triIndex2 = 0;
		int triIndex3 = 0; 
		int matIndex = 0;

		gnlVector3 color;
		color.set(1,0,0);

		for( unsigned int i = 0; i < scene->numberOfMeshes; i++){
			//renderAxis();
			for( unsigned int j = 0; j < scene->mesh[i]->numberOfTriangles; j++){
				
				triIndex1 = scene->mesh[i]->pTriangle[j].vertexIndex[0];
				triIndex2 = scene->mesh[i]->pTriangle[j].vertexIndex[1];
				triIndex3 = scene->mesh[i]->pTriangle[j].vertexIndex[2];
				
				matIndex = scene->mesh[i]->pTriangle[j].materialIndex;
				
				//if(matIndex>=0) /////////BUGADO
				if(scene->material[matIndex]->haveDiffuseTexture()){
					glEnable(GL_TEXTURE_2D);	
					glActiveTextureARB(GL_TEXTURE0);
					glBindTexture(GL_TEXTURE_2D, scene->material[matIndex]->diffuseTexture[0]->oglId);
					
				}else
					glDisable(GL_TEXTURE_2D);	

				//glActiveTextureARB(GL_TEXTURE1);
				//glBindTexture(GL_TEXTURE_2D, normalMap.oglId);
				

				unsigned int varBinormal = gnlShaderManager::getAttributeLocation(&shaderProgram, "rm_Binormal");
				unsigned int varTangent = gnlShaderManager::getAttributeLocation(&shaderProgram, "rm_Tangent");

				gnlShaderManager::setUniform(&shaderProgram, "baseMap", 0);
				//gnlShaderManager::setUniform(&shaderProgram, "bumpMap", 1);


				glBegin(GL_TRIANGLES);

				
				glMultiTexCoord2f(GL_TEXTURE0 , scene->mesh[i]->pTriangle[j].uvCoord[0].u, scene->mesh[i]->pTriangle[j].uvCoord[0].v);
				glNormal3f(scene->mesh[i]->pTriangle[j].normal[0].x, scene->mesh[i]->pTriangle[j].normal[0].y, scene->mesh[i]->pTriangle[j].normal[0].z);
				gnlShaderManager::setAttribute(&shaderProgram,varTangent,scene->mesh[i]->pTriangle[j].tangent[0]);
				gnlShaderManager::setAttribute(&shaderProgram,varBinormal,scene->mesh[i]->pTriangle[j].binormal[0]);
				//gnlShaderManager::setAttribute(&program, "color", color);
				glVertex3f(scene->mesh[i]->pVertex[triIndex1].x, scene->mesh[i]->pVertex[triIndex1].y, scene->mesh[i]->pVertex[triIndex1].z);
				
			
				glMultiTexCoord2f(GL_TEXTURE0 , scene->mesh[i]->pTriangle[j].uvCoord[1].u, scene->mesh[i]->pTriangle[j].uvCoord[1].v);
				glNormal3f(scene->mesh[i]->pTriangle[j].normal[1].x, scene->mesh[i]->pTriangle[j].normal[1].y, scene->mesh[i]->pTriangle[j].normal[1].z);
				gnlShaderManager::setAttribute(&shaderProgram, varTangent,scene->mesh[i]->pTriangle[j].tangent[1]);
				gnlShaderManager::setAttribute(&shaderProgram, varBinormal,scene->mesh[i]->pTriangle[j].binormal[1]);
				//gnlShaderManager::setAttribute(&program, "color", color);
				glVertex3f(scene->mesh[i]->pVertex[triIndex2].x, scene->mesh[i]->pVertex[triIndex2].y, scene->mesh[i]->pVertex[triIndex2].z);
								

				glMultiTexCoord2f(GL_TEXTURE0 , scene->mesh[i]->pTriangle[j].uvCoord[2].u, scene->mesh[i]->pTriangle[j].uvCoord[2].v);
				glNormal3f(scene->mesh[i]->pTriangle[j].normal[2].x, scene->mesh[i]->pTriangle[j].normal[2].y, scene->mesh[i]->pTriangle[j].normal[2].z);
				gnlShaderManager::setAttribute(&shaderProgram, varTangent,scene->mesh[i]->pTriangle[j].tangent[2]);
				gnlShaderManager::setAttribute(&shaderProgram, varBinormal,scene->mesh[i]->pTriangle[j].binormal[2]);
				//gnlShaderManager::setAttribute(&program, "color", color);
				glVertex3f(scene->mesh[i]->pVertex[triIndex3].x, scene->mesh[i]->pVertex[triIndex3].y, scene->mesh[i]->pVertex[triIndex3].z);
				glEnd();


				//Desenhando normais
				gnlVector3 p;
				p = scene->mesh[i]->pVertex[triIndex1] + scene->mesh[i]->pTriangle[j].normal[0] * 6;
				//p = p * 2;
				glDisable(GL_TEXTURE_2D);
				glPushMatrix();			
				glColor3f(1,1,1);
				
				glBegin(GL_LINES);
				glVertex3f(scene->mesh[i]->pVertex[triIndex1].x, scene->mesh[i]->pVertex[triIndex1].y, scene->mesh[i]->pVertex[triIndex1].z);
				glVertex3f(p.x, p.y, p.z);
				glEnd();

				p = scene->mesh[i]->pVertex[triIndex2] + scene->mesh[i]->pTriangle[j].normal[1] * 6;

				glBegin(GL_LINES);
				glVertex3f(scene->mesh[i]->pVertex[triIndex2].x, scene->mesh[i]->pVertex[triIndex2].y, scene->mesh[i]->pVertex[triIndex2].z);
				glVertex3f(p.x, p.y, p.z);
				glEnd();

				p = scene->mesh[i]->pVertex[triIndex3] + scene->mesh[i]->pTriangle[j].normal[2] * 6;

				glBegin(GL_LINES);
				glVertex3f(scene->mesh[i]->pVertex[triIndex3].x, scene->mesh[i]->pVertex[triIndex3].y, scene->mesh[i]->pVertex[triIndex3].z);
				glVertex3f(p.x, p.y, p.z);
				glEnd();
				glPopMatrix();
				//glLoadIdentity();

			}
		
		}
	}



	
/*
	void renderAll(gnlShaderProgram& gProgram,  float*  gBackColor){
		gnlScene *scene = pGNLScene;
		int triIndex1 = 0;
		int triIndex2 = 0;
		int triIndex3 = 0; 
		int matIndex = 0;

		for( unsigned int i = 0; i < scene->numberOfMeshes; i++){
			//renderAxis();
			for( unsigned int j = 0; j < scene->mesh[i]->numberOfTriangles; j++){
				
				triIndex1 = scene->mesh[i]->pTriangle[j].vertexIndex[0];
				triIndex2 = scene->mesh[i]->pTriangle[j].vertexIndex[1];
				triIndex3 = scene->mesh[i]->pTriangle[j].vertexIndex[2];
				
				matIndex = scene->mesh[i]->pTriangle[j].materialIndex;
				
				//if(matIndex>=0) /////////BUGADO
				if(scene->material[matIndex]->haveDiffuseTexture()){
					glEnable(GL_TEXTURE_2D);	
					glBindTexture(GL_TEXTURE_2D, scene->material[matIndex]->diffuseTexture[0]->oglId);
				}else
					glDisable(GL_TEXTURE_2D);	

				//float color[] = {gBackColor, gBackColor.y, gBackColor.z};
				
				unsigned int varLocationId = gnlShaderManager::getAttributeLocation(&gProgram, "color");
					
				glBegin(GL_TRIANGLES);

				glVertexAttrib3f(varLocationId, gBackColor[0], gBackColor[1], gBackColor[2]);
				glTexCoord2f(scene->mesh[i]->pTriangle[j].uvCoord[0].u, scene->mesh[i]->pTriangle[j].uvCoord[0].v);
				glVertex3f(scene->mesh[i]->pVertex[triIndex1].x, scene->mesh[i]->pVertex[triIndex1].y, scene->mesh[i]->pVertex[triIndex1].z);
				
				glTexCoord2f(scene->mesh[i]->pTriangle[j].uvCoord[1].u, scene->mesh[i]->pTriangle[j].uvCoord[1].v);
				glVertex3f(scene->mesh[i]->pVertex[triIndex2].x, scene->mesh[i]->pVertex[triIndex2].y, scene->mesh[i]->pVertex[triIndex2].z);
				
				glTexCoord2f(scene->mesh[i]->pTriangle[j].uvCoord[2].u, scene->mesh[i]->pTriangle[j].uvCoord[2].v);
				glVertex3f(scene->mesh[i]->pVertex[triIndex3].x, scene->mesh[i]->pVertex[triIndex3].y, scene->mesh[i]->pVertex[triIndex3].z);
				glEnd();

				//gnlShaderManager::useFixedProgram();
				/*
				gnlVector3 p;
				p = scene->mesh[i]->pVertex[triIndex1] + scene->mesh[i]->pTriangle[j].normal[0] * 6;
				//p = p * 2;
				glDisable(GL_TEXTURE_2D);
				glPushMatrix();			
				glColor3f(1,1,1);
				
				glBegin(GL_LINES);
				glVertex3f(scene->mesh[i]->pVertex[triIndex1].x, scene->mesh[i]->pVertex[triIndex1].y, scene->mesh[i]->pVertex[triIndex1].z);
				glVertex3f(p.x, p.y, p.z);
				glEnd();

				p = scene->mesh[i]->pVertex[triIndex2] + scene->mesh[i]->pTriangle[j].normal[1] * 6;

				glBegin(GL_LINES);
				glVertex3f(scene->mesh[i]->pVertex[triIndex2].x, scene->mesh[i]->pVertex[triIndex2].y, scene->mesh[i]->pVertex[triIndex2].z);
				glVertex3f(p.x, p.y, p.z);
				glEnd();

				p = scene->mesh[i]->pVertex[triIndex3] + scene->mesh[i]->pTriangle[j].normal[2] * 6;

				glBegin(GL_LINES);
				glVertex3f(scene->mesh[i]->pVertex[triIndex3].x, scene->mesh[i]->pVertex[triIndex3].y, scene->mesh[i]->pVertex[triIndex3].z);
				glVertex3f(p.x, p.y, p.z);
				glEnd();
				glPopMatrix();
				//glLoadIdentity();

			}
		
		}
	}
*/
	float *getMaterial(int meshIndex){


	}
	/*
	int exportModel(const char *fileName); //export in gnl format
	void renderAll();
	void renderMesh(int meshId);
	void renderMesh(const char* const meshName);
	
	*/
};

#endif